﻿namespace OutLook.Model.Domains
{
    using System;
    using System.Xml.Serialization;
    using OutLook.Model.Infrastructure;
    using System.Runtime.Serialization;

    /// <summary>
    /// Chemical Сombination
    /// </summary>
    [DataContract]
    public class ChemicalСombination : IEquatable<ChemicalСombination>, IAssignable, IValidatable
    {
        #region Constructors

        /// <summary>
        /// Initializes new default instance of Chemical Сombination
        /// </summary>
        public ChemicalСombination() : this(string.Empty, 0.0d) { }

        /// <summary>
        /// Initializes new instance of Chemical Сombination
        /// </summary>
        /// <param name="element">Element name</param>
        /// <param name="percentage">Percentage in substance</param>
        public ChemicalСombination(string element, double percentage)
        {
            m_Element = element;
            m_Percentage = percentage;
        }

        #endregion

        #region Properties

        /// <summary>
        /// The title of element
        /// </summary>
        [DataMember]
        public string Element
        {
            get { return m_Element; }
            private set { m_Element = value; }
        }

        /// <summary>
        /// The content of element in composition (in percents)
        /// </summary>
        [DataMember]
        public double Percentage
        {
            get { return m_Percentage; }
            set { m_Percentage = value; }
        }

        /// <summary>
        /// The content of element in composition (in weight)
        /// </summary>
        public double Weight
        {
            get { return m_Weight; }
            set { m_Weight = value; }
        }

        #endregion

        #region IEquatable<Composition> Implementation

        /// <summary>
        /// Compares current Chemical Сombination with another one
        /// </summary>
        /// <param name="other">Another Chemical Сombination</param>
        /// <returns>True - If current Chemical Сombination and another one are equal, otherwise -False</returns>
        public bool Equals(ChemicalСombination other)
        {
            if (other == null)
                return false;

            if (Element.Equals(other.Element) && Percentage == other.Percentage && Weight == other.Weight)
                return true;

            return false;
        }

        #endregion

        #region Equals by characteristics

        /// <summary>
        /// Compares current Chemical Сombination with another one by name and percentage
        /// </summary>
        /// <param name="other">Another Chemical Сombination</param>
        /// <returns>True - If current Chemical Сombination and another one are equal by name and percentage, otherwise -False</returns>
        public bool EqualsByPercentage(ChemicalСombination other)
        {
            if (other == null)
                return false;

            if (Element.Equals(other.Element) && Percentage == other.Percentage)
                return true;

            return false;
        }

        /// <summary>
        /// Compares current Chemical Сombination with another one by name and weight
        /// </summary>
        /// <param name="other">Another Chemical Сombination</param>
        /// <returns>True - If current Chemical Сombination and another one are equal by name and weight, otherwise -False</returns>
        public bool EqualsByWeight(ChemicalСombination other)
        {
            if (other == null)
                return false;

            if (Element.Equals(other.Element) && Weight == other.Weight)
                return true;

            return false;
        }

        #endregion

        #region IAssignable Implementation

        /// <summary>
        /// Assigns values of current Chemical Сombination to the argument object
        /// </summary>
        /// <param name="obj">Object to assign to</param>
        /// <exception cref="ArgumentNullException">If object to assign to is nullable</exception>
        /// <exception cref="NotSupportedException">If object to assign to doesn't fit</exception>
        public void AssignTo(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException();

            if (obj is ChemicalСombination)
            {
                ChemicalСombination composition = obj as ChemicalСombination;
                composition.Percentage = Percentage;
                composition.Element = Element;
                composition.Weight = Weight;

                return;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region IValidatable Implementation

        /// <summary>
        /// Validates Chemical Сombination
        /// </summary>
        /// <returns>True - if current Chemical Сombination is valid, otherwise - false</returns>
        public bool Validate()
        {
            if (string.IsNullOrEmpty(Element) || string.IsNullOrWhiteSpace(Element))
                return false;

            if (Percentage < 0)
                return false;

            if (Weight < 0)
                return false;

            return true;
        }

        #endregion

        #region Fields

        private string m_Element = default(string);
        private double m_Percentage = default(double);
        private double m_Weight = default(double);

        #endregion
    }
}
